package cz.myslivec.slovicka.xml;

import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.List;

import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.international.StatusMessage;
import org.jboss.seam.international.StatusMessages;
import org.jboss.seam.log.Log;

import cz.myslivec.slovicka.dao.LessonDao;
import cz.myslivec.slovicka.dao.TestedVocableDao;
import cz.myslivec.slovicka.dao.VocableTypeDao;
import cz.myslivec.slovicka.entity.Lesson;
import cz.myslivec.slovicka.entity.TestedVocable;
import cz.myslivec.slovicka.entity.Vocable;
import cz.myslivec.slovicka.xml.converter.LessonConverter;
import cz.myslivec.slovicka.xml.converter.TestedVocableConverter;
import cz.myslivec.slovicka.xml.model.LessonDTO;
import cz.myslivec.slovicka.xml.model.TestedVocableDTO;
import cz.myslivec.slovicka.xml.model.VocablesDbDTO;

@Name("exportImportProcessor")
@AutoCreate
public class ExportImportProcessor implements Serializable {
	private static final long serialVersionUID = -6216857611816697744L;
	
	@Logger
	private Log log;

	@In
	private EntityManager entityManager;

	@In LessonDao lessonDao;
	@In LessonConverter lessonConverter;
	@In TestedVocableDao testedVocableDao;
	@In TestedVocableConverter testedVocableConverter;
	@In VocableTypeDao vocableTypeDao;
	
	// EXPORT
	public void exportDB() {
		List<LessonDTO> lessons = lessonConverter.convertList(lessonDao.list());
		List<TestedVocableDTO> tvDTOs = testedVocableConverter.convertList(testedVocableDao.list());
    	if(lessons == null || lessons.isEmpty()) {
    		return;
    	}

    	VocablesDbDTO dbDTO = new VocablesDbDTO(lessons, tvDTOs);
    	
    	Marshaller marshaller;
    	try {
	    	JAXBContext jaxbContext = JAXBContext.newInstance(VocablesDbDTO.class);
			marshaller = jaxbContext.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
    	} catch(JAXBException ex) {
    		ex.printStackTrace();
    		return;
    	}
    	
        FacesContext fc = FacesContext.getCurrentInstance(); 
        HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse(); 
        response.setContentType("application/force-download");
        response.setCharacterEncoding("UTF-8");
        String downloadFile = "exported_vocables";
        response.addHeader("Content-Disposition", "attachment; filename=\"" + downloadFile + "\"");
        
        try {
        	PrintWriter out = response.getWriter();
        	marshaller.marshal(dbDTO, out);
        	out.close();
          
//        	StringWriter strOut = new StringWriter();
//        	marshaller.marshal(dbDTO, strOut);
//        	log.info("<><> {0}", strOut.toString());
        } catch (Exception exc){
          exc.printStackTrace();
        } 
        
        fc.responseComplete();
	}
	
	// IMPORT
	public void importDB(InputStream inputStream) {
		if (inputStream != null) {
			Unmarshaller unmarshaller;
			VocablesDbDTO vocablesDbDTO;
	    	try {
		    	JAXBContext jaxbContext = JAXBContext.newInstance(VocablesDbDTO.class);
		    	unmarshaller = jaxbContext.createUnmarshaller();
		    	vocablesDbDTO = (VocablesDbDTO) unmarshaller.unmarshal(inputStream);
	    	} catch(Exception ex) {
	    		ex.printStackTrace();
	    		return;
	    	}
	    	
	    	if(vocablesDbDTO == null) {
	    		return;
	    	}
	    	
	    	log.info("imported data: {0}", vocablesDbDTO.toString());
	    	
	    	saveVocablesDbDTO(vocablesDbDTO);
		} else {
			StatusMessages.instance().addFromResourceBundle(StatusMessage.Severity.ERROR, "menu-setup.initial-load.xhtml.error.file_not_provided");
		}
	}

	private void saveVocablesDbDTO(VocablesDbDTO data) {
		if(data == null) {
			return;
		}
		
		List<LessonDTO> lessonsDTO = data.getLessons();
		List<TestedVocableDTO> testedVocablesDTO = data.getTestedVocables();

		if(lessonsDTO == null || lessonsDTO.isEmpty()) {
			return;
		}
		
		List<Lesson> lessons = lessonConverter.convertBackList(lessonsDTO);
		List<TestedVocable> testedVocables = testedVocableConverter.convertBackList(testedVocablesDTO);
		
		for(Lesson lesson : lessons) {
			if(vocableTypeDao.get(lesson.getVocType().getCode()) == null) {
				entityManager.persist(lesson.getVocType());
			}
			
			List<Vocable> vocables = lesson.getVocables();
			if(vocables != null && !vocables.isEmpty()) {
				for(Vocable vocable : vocables) {
					Long vocableId = vocable.getId();
					vocable.setId(null);
					entityManager.persist(vocable);
					
					if(testedVocables != null && !testedVocables.isEmpty()) {
						for(TestedVocable testedVocable : testedVocables) {
							if(testedVocable.getVocableId() != null && vocableId != null &&
									testedVocable.getVocableId().equals(vocableId)) {
								
								testedVocable.setVocable(vocable);
								testedVocable.setId(null);
								entityManager.persist(testedVocable);
							}
						} 
					}
					
				}
			}
			lesson.setId(null);
			entityManager.persist(lesson);
		}
		
		entityManager.flush();
	}
	
}
